package com.snake.excel2java.excel;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.util.LinkedHashMap;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import lombok.Getter;

@Slf4j
public abstract class ExcelLoader<T extends IExcelRowLoader> implements IExcelLoader {

	public static final int START_LINE = 5;
	
	// 从头遍历
	@Getter
	protected LinkedHashMap<Integer, T> dataMap;
	private Class<T> entityClass; 
	
	// 加载时间
	protected long loadTime;
	
	private Class<T> getEntityClass() {  
		
        if (entityClass == null)  
            entityClass = (Class<T>) ((ParameterizedType) getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()[0];   

        return entityClass;  
    }
	
	private T newInstance() {
		
		try {
			return getEntityClass().newInstance();
		} catch (Exception e) {

			log.error("{} create newInstance error: message = {}", getFileName(), e.getMessage());
			
			e.printStackTrace();
		}
		
		return null;
	}
	
	public T getRow(int id) {
		return dataMap.get(id);
	}
	
	public long getLoadTime() {
		return loadTime;
	}
	
	@Override
	public boolean load(String path) {
		
		boolean result = true;
		int index = START_LINE;
		XSSFWorkbook workbook2007 = null;
		try {
			
			workbook2007 = new XSSFWorkbook(path + getFileName());
			XSSFSheet sheet = workbook2007.getSheetAt(0);
			
//			FormulaEvaluator evaluator = sheet.getWorkbook()
//											  .getCreationHelper()
//											  .createFormulaEvaluator();  
//			evaluator.evaluateAll();
			
			String[] propNames = getPropNames();
			int[] dataIndex = new int[propNames.length];
			XSSFRow nameRow = sheet.getRow(index - 1);
			
			int width = nameRow.getLastCellNum();
			String[] nowNames = new String[width];
			for(int i = 0; i < width; ++i) 
				nowNames[i] = readString(nameRow, i, StringType.STRING);
			
			for(int i = 0; i < propNames.length; ++i) {
				
				String name = propNames[i];
				
				int j = 0;
				for(; j < nowNames.length; ++j) {
					
					if(nowNames[j].equals(name))
						break;
					
				}
				
				if(j >= nowNames.length) {
					
					log.error("没有找到列: {}", name);
					throw new Exception("没有找到列");
				}
					
				
				dataIndex[i] = j;
				
			}

			
			int length = sheet.getLastRowNum() + 1;
			
			LinkedHashMap<Integer, T> map = new LinkedHashMap<Integer, T>(length, 0.75f, false);
			for( ; index < length; ++index) {
				
				XSSFRow row = sheet.getRow(index);
				
				if(null == row)
					continue;
				
				int id = readInt(row, 0);
				
//				if(0 == id && START_LINE != index)
				if(0 == id)
					continue;
				
				T t = newInstance();
				t.load(row, dataIndex);
								
//				log.info(t.toString());
				
				map.put(t.getId(), t);
				
			}
			
			dataMap = map;
			loadTime = System.currentTimeMillis();
			
			parse();
			
			log.info("file {} load {} lines, desc: {}\r\n\r\n", getFileName(), dataMap.size(), getDesc());
			
		} catch (Exception e) {
			
			log.error("read file {} error int line {}........", getFileName(), index);
						
			e.printStackTrace();
			
			result = false;
			
		} finally {
			
			try {
				workbook2007.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				
				log.error("close file {} error: {}", getFileName(), e.getMessage());
			}
		}
		
		return result;
	}
	
	protected int readInt(XSSFRow row, int index) {	
		
		try {
			XSSFCell cell = row.getCell(index);
			
			
			if(null == cell)
				return 0;
			
			switch (cell.getCellType()) {
			case BLANK:
				
				return 0;
				
			case STRING: 
				
				String value = cell.getStringCellValue();
				
				if(null == value)
					return 0;
				
				return Integer.parseInt(value.trim());
				
			default:
				break;
			}
			
			return Double.valueOf(cell.getNumericCellValue()).intValue();
		} catch (Exception e) {
			e.printStackTrace();
			log.error("int - read column {} error in row {}......", index, row.getRowNum());
		}
		
		return 0;
	}
	
	
	public static final String EMPTY = "";
	protected String readString(XSSFRow row, int index, StringType type) {
		
		try {
			XSSFCell cell = row.getCell(index);
			
			if(null == cell)
				return "";
			
			CellType cellType = cell.getCellType();
			
			switch (cellType) {
			case BLANK:
				
				return EMPTY;
				
			case BOOLEAN:
			
				return EMPTY + cell.getBooleanCellValue();
				
			case NUMERIC:
				
				switch (type) {
				case INT_ARRAY:
					
					return EMPTY + Double.valueOf(cell.getNumericCellValue()).intValue();
				case FLOA_TARRAY:
					
					return EMPTY + Double.valueOf(cell.getNumericCellValue()).floatValue();
				case DOUBLE_ARRAY:
					
					return EMPTY + cell.getNumericCellValue();

				default:
					return EMPTY + cell.getNumericCellValue();
						
				}
			

			default:
				break;
			}
			
			String value = cell.getStringCellValue();
			
			if(null == value)
				return "";
			
			return value.trim();
			
		} catch (Exception e) {
			e.printStackTrace();
			log.error("string - read column {} error in row {}......", index, row.getRowNum());
		}
		
		return EMPTY;
	}

	
	// 加载完成后，做其他操作
	protected void parse() {
		
	}
}
